/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024.
 * Description: provide audit optimization
 * Author: dongxinhua <dongxinhua@huawei.com>
 * Create: 2024-03-08
 */
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/cpumask.h>
#include <linux/seq_file.h>

static cpumask_var_t audit_cpu_affinity __read_mostly;

static int audit_cpu_affinity_show(struct seq_file *m, void *v)
{
	seq_printf(m, "%*pbl\n", cpumask_pr_args(audit_cpu_affinity));
	return 0;
}

static ssize_t audit_cpu_affinity_write(struct file *file,
		const char __user *buffer, size_t count, loff_t *ppos)
{
	cpumask_var_t new_value;
	int err;

	if (!zalloc_cpumask_var(&new_value, GFP_KERNEL))
		return -ENOMEM;

	err = cpumask_parselist_user(buffer, count, new_value);
	if (err)
		goto out;

	err = cpumask_subset(new_value, cpu_online_mask);
	if (!err) {
		err = -EINVAL;
		goto out;
	}

	cpumask_copy(audit_cpu_affinity, new_value);
	err = count;

out:
	free_cpumask_var(new_value);
	return err;
}

static int audit_cpu_affinity_open(struct inode *inode, struct file *file)
{
	return single_open(file, audit_cpu_affinity_show, PDE_DATA(inode));
}

static const struct proc_ops audit_cpu_affinity_proc_ops = {
	.proc_open	= audit_cpu_affinity_open,
	.proc_read	= seq_read,
	.proc_lseek	= seq_lseek,
	.proc_release	= single_release,
	.proc_write	= audit_cpu_affinity_write,
};

int audit_cpu_affinity_init(void)
{
	if (!cpumask_available(audit_cpu_affinity)) {
		if (!zalloc_cpumask_var(&audit_cpu_affinity, GFP_KERNEL)) {
			pr_err("fail allocating mask!\n");
			return -ENOMEM;
		}
	}
	if (cpumask_empty(audit_cpu_affinity))
		cpumask_setall(audit_cpu_affinity);

	if (!proc_create("audit_cpu_affinity", 0640, NULL, &audit_cpu_affinity_proc_ops)) {
		pr_err("audit cpu affinity proc create failed!\n");
		free_cpumask_var(audit_cpu_affinity);
		return -ENOMEM;
	}

	pr_info("audit cpu affinity init success\n");
	return 0;
}

inline bool audit_is_affinity_cpu(int cpu)
{
	if (cpumask_available(audit_cpu_affinity))
		return cpumask_test_cpu(cpu, audit_cpu_affinity);
	return false;
}
